> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/Anny26022/chartsmaze_clone/llms.txt
> Use this file to discover all available pages before exploring further.

# fetch_incremental_price_bands.py

> Fetches daily price band changes from NSE Archives CSV files

## Overview

Fetches the latest daily price band changes (circuit limit revisions) from NSE Archives. The script checks the last 7 days backwards from today to find the most recent CSV file, as NSE does not publish these files on weekends or holidays.

**Source:** `fetch_incremental_price_bands.py`\
**Phase:** Phase 2 (Enrichment)\
**Output:** `incremental_price_bands.json`

## Data Source

### NSE Archives CSV Endpoint

```
GET https://nsearchives.nseindia.com/content/equities/eq_band_changes_{date}.csv
```

<ParamField path="date" type="string" required>
  Date in `ddmmyyyy` format (e.g., `03032024` for March 3, 2024)
</ParamField>

### Example URL

```
https://nsearchives.nseindia.com/content/equities/eq_band_changes_03032024.csv
```

## CSV Format

The NSE CSV contains the following structure (example):

```csv theme={null}
Symbol,Series,Date,New Band,Old Band,Applicable Date
RELIANCE,EQ,03-MAR-2024,10,20,04-MAR-2024
TATASTEEL,EQ,03-MAR-2024,20,10,04-MAR-2024
```

## Function Signature

```python theme={null}
def fetch_nse_price_bands():
    """
    Fetches the latest price band changes CSV from NSE Archives.
    Searches backwards up to 7 days to find the most recent file.
    Parses CSV using pandas and saves as JSON.
    """
```

## Date Search Logic

Searches backwards from today up to 7 days:

```python theme={null}
today = datetime.now()
clean_data = []

for i in range(8):  # 0-7 days back
    check_date = today - timedelta(days=i)
    date_str = check_date.strftime("%d%m%Y")  # Format: ddmmyyyy 
    url = base_url.format(date=date_str)
    
    response = requests.get(url, headers=headers, timeout=10)
    if response.status_code == 200:
        # Found the file, parse and break
        break
```

## CSV Parsing

Uses pandas for robust CSV parsing:

```python theme={null}
csv_content = response.content.decode('utf-8')
df = pd.read_csv(io.StringIO(csv_content))

# Convert to list of dictionaries
raw_data = df.to_dict(orient='records')

# Clean whitespace from keys and values
for record in raw_data:
    cleaned_record = {}
    for k, v in record.items():
        key = k.strip() if isinstance(k, str) else k
        value = v.strip() if isinstance(v, str) else v
        cleaned_record[key] = value
    clean_data.append(cleaned_record)
```

## Output Structure

<ResponseField name="Symbol" type="string">
  Stock trading symbol
</ResponseField>

<ResponseField name="Series" type="string">
  Series type (typically "EQ" for equity)
</ResponseField>

<ResponseField name="Date" type="string">
  Date of band change announcement
</ResponseField>

<ResponseField name="New Band" type="string">
  New circuit limit percentage
</ResponseField>

<ResponseField name="Old Band" type="string">
  Previous circuit limit percentage
</ResponseField>

<ResponseField name="Applicable Date" type="string">
  Date when new band becomes effective
</ResponseField>

### Example Output

```json theme={null}
[
  {
    "Symbol": "RELIANCE",
    "Series": "EQ",
    "Date": "03-MAR-2024",
    "New Band": "10",
    "Old Band": "20",
    "Applicable Date": "04-MAR-2024"
  },
  {
    "Symbol": "TATASTEEL",
    "Series": "EQ",
    "Date": "03-MAR-2024",
    "New Band": "20",
    "Old Band": "10",
    "Applicable Date": "04-MAR-2024"
  }
]
```

## Dependencies

* `requests` — HTTP client for downloading CSV
* `json` — JSON serialization
* `datetime` — Date calculations
* `pandas` — CSV parsing and data manipulation
* `io` — In-memory file handling for CSV parsing

## HTTP Headers

```python theme={null}
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
    "Accept": "*/*"
}
```

## Error Handling

* 10-second timeout per HTTP request
* Gracefully handles 404 (file not found) for non-trading days
* Continues searching backwards through date range
* Reports parse errors but continues to next date

```python theme={null}
if response.status_code == 200:
    print(f"  Found data for {date_str}!")
    # Parse and break
elif response.status_code == 404:
    print(f"  No file found for {date_str} (404).")
else:
    print(f"  Unexpected status {response.status_code} for {date_str}.")
```

## Usage Example

```bash theme={null}
python3 fetch_incremental_price_bands.py
```

**Expected Output:**

```
Checking for price band changes on 03032024...
  Found data for 03032024!
Successfully saved 15 price band changes to incremental_price_bands.json
```

**On Weekend/Holiday:**

```
Checking for price band changes on 03032024...
  No file found for 03032024 (404).
Checking for price band changes on 02032024...
  No file found for 02032024 (404).
Checking for price band changes on 01032024...
  Found data for 01032024!
Successfully saved 12 price band changes to incremental_price_bands.json
```

## Integration

This script is part of **Phase 2 (Enrichment)** in the EDL Pipeline. The output file is consumed by:

* `add_corporate_events.py` — Adds "#: +/- Revision" event markers for price band changes
* `bulk_market_analyzer.py` — Updates the "Circuit Limit" field

Run via master pipeline:

```bash theme={null}
python3 run_full_pipeline.py
```

## Data Availability Notes

* NSE typically publishes this file on trading days only
* File is usually available after market close (3:30 PM IST)
* Weekends and holidays will have no file (404 response)
* The 7-day search window ensures catching the latest file even after long weekends

## Field Interpretation

<Info>
  **Band Meanings:**

  * `2%` — Very high surveillance/volatility
  * `5%` — High surveillance
  * `10%` — Moderate surveillance
  * `20%` — Normal (standard circuit limit)

  Lower band values indicate tighter restrictions and higher regulatory scrutiny.
</Info>
